﻿using System;
using System.Linq;

namespace LaoLuo.Threading
{
    /// <summary>
    /// collection of <see cref="WorkHandler&lt;T&gt;"/>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class WorkHandlerCollection<T> : IDisposable
    {
        private const int DefaultWorkerCount = 4;
        private readonly int _workerCount = DefaultWorkerCount;
        private WorkHandler<T>[] _workers;

        /// <summary>
        /// init a <see cref="WorkHandlerCollection&lt;T&gt;"/>
        /// </summary>
        /// <param name="duty"></param>
        /// <param name="workerCount"></param>
        /// <param name="amountPerBatch"> </param>
        public WorkHandlerCollection(Action<T> duty, int workerCount = DefaultWorkerCount, int amountPerBatch = WorkHandler<T>.DefaultAmountPerBatch)
        {
            if (workerCount > 0)
            {
                _workerCount = workerCount;
            }

            _workers = new WorkHandler<T>[_workerCount];
            for (var j = 0; j < _workerCount; j++)
            {
                _workers[j] = new WorkHandler<T>(duty, amountPerBatch);
            }

        }

        /// <summary>
        /// current length of queue
        /// </summary>
        public int QueueCount { get { return _workers.Sum(i => i.QueueCount); } }

        /// <summary>
        /// current count of work in processing
        /// </summary>
        public int ProcessingCount { get { return _workers.Sum(i => i.ProcessingCount); } }

        /// <summary>
        /// count of work in queue and in processing
        /// </summary>
        public int ToHandleCount { get { return _workers.Sum(i => i.ToHandleCount); } }

        /// <summary>
        /// get <see cref="WorkHandler&lt;T&gt;"/> with specified <see cref="index"/>
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public WorkHandler<T> this[int index]
        {
            get
            {
                if (index > _workers.Length - 1)
                {
                    return null;
                }

                return _workers[index];
            }
        }

        /// <summary>
        /// add a work to the queue
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public int AddWork(T item)
        {
            var handler = GetHandler();
            var ret = Array.IndexOf(_workers, handler);
            handler.AddWork(item);
            return ret;
        }

        /// <summary>
        /// stop the handlers and dispose managed resources
        /// </summary>
        public void Dispose()
        {
            foreach (var workHandler in _workers)
            {
                workHandler.Dispose();
            }

            _workers = null;
        }

        private WorkHandler<T> GetHandler()
        {
            return _workers.OrderBy(i => i.QueueCount).First();
        }
    }
}
